#pragma once
#include "basic_component/common.hpp"
#include "basic_component/Log.hpp"
#include <jsoncpp/json/json.h>
#include "basic_component/Socket.hpp"


class request //请求协议
{
public:
    request(int x = 0, int y = 0, char oper = '\0')
        :_x(x)
        ,_y(y)
        ,_oper(oper)
    {}

    //序列化: 结构数据 -> 字符串
    bool serialize(std::string& out_str/*输出型参数*/)
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        out_str = writer.write(root);
        return true;
    }

    //反序列化: 字符串 -> 结构数据
    bool deserialize(const std::string& in_str)
    {
        Json::Value root;
        Json::Reader reader;
        bool ret_parse = reader.parse(in_str, root);
        if(ret_parse)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ret_parse;
    }

    int get_x() const
    {
        return _x;
    }
    int get_y() const
    {
        return _y;
    }
    char get_oper() const
    {
        return _oper;
    }

    int& get_x_ref()
    {
        return _x;
    }
    int& get_y_ref()
    {
        return _y;
    }
    char& get_oper_ref()
    {
        return _oper;
    }


private:
    int _x;
    int _y;
    char _oper;
};


enum RESPONSE_CODE
{
    RESPONSE_NORMAL = 0,
    DIVISION_ZERO_ERR, /*除0*/
    MODULO_ZERO_ERR, /*取模0*/
    OPERATOR_UNKNOWN /*运算符不认识*/
};

class response //应答协议
{
public:
    response(int result = 0, int code = RESPONSE_NORMAL)
        :_result(result)
        ,_code(code)
    {}

    //序列化: 结构数据 -> 字符串
    bool serialize(std::string& out_str/*输出型参数*/)
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        out_str = writer.write(root);
        return true;
    }

    //反序列化: 字符串 -> 结构数据
    bool deserialize(const std::string& in_str)
    {
        Json::Value root;
        Json::Reader reader;
        bool ret_parse = reader.parse(in_str, root);
        if(ret_parse)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ret_parse;
    }

    void set_result(int result)
    {
        _result = result;
    }
    void set_code(int code)
    {
        _code = code;
    }

    int get_result() const
    {
        return _result;
    }
    int get_code() const
    {
        return _code;
    }

private:
    int _result;
    int _code;
};



using func_t = std::function<response(const request&)>;


//                 报头     有效载荷
//自定义应用层协议: [len]\r\n[message]\r\n           约定\r\n不属于报文的一部分, 是用来分割报头和有效载荷的

// 协议(基于TCP的)需要解决两个问题：
// 1. request和response必须得有序列化和反序列化功能
// 2. 你必须保证，读取的时候，读到[完整的请求](TCP, UDP不用考虑)!!!
class protocol
{
public: 
    const static inline std::string default_sep = "\r\n";//静态内联成员, 可以看thread_pool.hpp文件的详细解释

    protocol()//client调用 -- 因为处理逻辑很简单,所以就不和server一样回调到上层处理报文了, 直接函数内实现
    {}

    protocol(const func_t& handle_func)//server调用
        :_handle_func(handle_func)
    {}


    //封装
    std::string pack(const std::string& message)
    {
        std::string message_len = std::to_string(message.size());
        return message_len + default_sep + message + default_sep; //[len]\r\n[message]\r\n  
    }

    //解包
    // 1. 判断报文完整性
    // 2. 如果包含至少一个完整请求，就提取他, 并从移除它方便处理下一个
    //                       输入输出                                输出
    bool unpack(std::string& package/*不一定是完整的*/, std::string& message)
    {
        // 一个完整报文: 32\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n
        // 可能read到package里的情况: 
        // 情况1: 3
        // 情况2: 32
        // 情况3: 32\r
        // 情况4: 32\r\n
        // 情况5: 32\r\n{"x": 10, "y" : 2
        // 情况6: 32\r\n{"x": 10, "y" : 20, "oper" : '+'}\r\n32\r\n{"x": 10,
        // ......

        auto pos = package.find(default_sep);
        if(pos == std::string::npos)//情况1,2,3
            return false;

        std::string message_len_str = package.substr(0, pos);//[0, pos)
        size_t message_len = std::stoi(message_len_str);
        size_t complete_package_len = message_len_str.size() + message_len + 2 * default_sep.size();
        if(package.size() < complete_package_len)//情况4,5
            return false;

        //走到这里, 代表package里一定包含至少一个完整报文
        std::string complete_package = package.substr(0, complete_package_len);//提取
        package.erase(0, complete_package_len);//移除
        
        //解包 提取有效载荷
        message = complete_package.substr(message_len_str.size() + default_sep.size(), complete_package.size() - default_sep.size());
        return true;
    }



    //server调用
    //这里做一下对reactor_server的适配, 因为其内部已经做了读取和发送报文相关的模块, protocol里只需要对报文进行处理即可
    // void receive_request_and_send_response(std::shared_ptr<Socket>& sock_p, const Inet_Addr& client)
    bool data_stream_handler(std::string& in_buffer/*io_connection的读缓冲区*/, std::string& out_buffer/*io_connection的写缓冲区*/)
    {
        bool out_package_exist_flag = false;

        //1.对传入数据流进行解包(判断完整性和粘包提取)和判断
        std::string in_message_str;

        //为什么用while 不用if? : 如果传入数据流中有多个报文, 可连续处理. 
        //即: 报文不完整, 返回false, 让底层(reactor_server层)继续接收; 报文完整, 继续处理in_buffer -- 可以避免报文积压
        while(unpack(in_buffer, in_message_str))
        {
            //2.反序列化请求报文
            request in_message_struct;
            in_message_struct.deserialize(in_message_str);

            //3.处理报文 -- 交给上层(应用层: calculate)
            response out_message_struct = _handle_func(in_message_struct);

            //4.序列化应答报文
            std::string out_message_str;
            out_message_struct.serialize(out_message_str);

            //5.封装
            std::string out_package = pack(out_message_str);

            //6.将待发送包裹传出函数
            out_buffer += out_package;//注意是+=
            out_package_exist_flag = true;
        }

        return out_package_exist_flag;
    }



    //client调用
    void send_request_and_receive_response(std::shared_ptr<Socket>& sock_p, const Inet_Addr& server)
    {
        std::string out_buffer;//读取缓冲区
        while(true)
        {
            //1.从cin里获取请求
            request send_message_struct;
            std::cout << "please enter x:> ";
            std::cin >> send_message_struct.get_x_ref();
            std::cout << "please enter operator:> ";
            std::cin >> send_message_struct.get_oper_ref();
            std::cout << "please enter y:> ";
            std::cin >> send_message_struct.get_y_ref();

            //2.序列化请求报文
            std::string send_message_str;
            send_message_struct.serialize(send_message_str);

            //3.封装 -- 添加协议报头
            std::string send_package = pack(send_message_str);

            //4.发送
            if(sock_p->send(send_package) == false)
            {
                LOG(wzx::log_level::FATAL) << "send fail!!!";
                exit(SEND_ERR);
            }

            //5.读取sockfd, 接受应答报文
            if(sock_p->receive(out_buffer) == false) //服务端关闭了
                break;

            //6.解包
            std::string recv_message_str;
            // if(unpack(out_buffer, recv_message_str) == false)// -- 法1: 报文不完整, 继续接收
            // {
            //     LOG(wzx::log_level::WARNING) << "unpack fail~~~";
            //     continue;
            // }//此时message一定是完整的有效载荷
            while(unpack(out_buffer, recv_message_str))// -- 法2: 报文不完整, 继续接收; 报文完整, 继续处理 -- 可以避免报文积压
            {
                //7.反序列化应答报文
                response recv_message_struct;
                recv_message_struct.deserialize(recv_message_str);

                //8.展示结果 -- 这里就不和server一样回调到上层处理报文了, 因为处理逻辑很简单, 直接函数内实现
                if(recv_message_struct.get_code() == 0)//计算正常
                    std::cout << "result:> " << recv_message_struct.get_result() << std::endl;
                else
                    std::cout << "calculate err, err_code:> " << recv_message_struct.get_code() << std::endl;

                std::cout << "-----------------------------------" << std::endl;
            }

        }

    }


private:
    func_t _handle_func;
};
